using System;
using System.Collections.Generic;
using System.Text;
using DTLAutomate;
using DTLAutomate.Layout;

namespace DTLAutomateCLI
{
	class Program
	{
		static SensorDriver sensorDriver;
		static APIControl controlDriver;
		static LogicalLayout layout;

		static void Main(string[] args)
		{
			if (args.Length == 2)
			{
				sensorDriver = new SensorDriver(args[1]);
				controlDriver = new APIControl(args[0]);
			}
			else if (args.Length == 0)
			{
				sensorDriver = new SensorDriver();
				controlDriver = new APIControl();
			}
			else
			{
				System.Console.Error.WriteLine("Usage: DTLAutomateCLI [<control port name> <sensor port name>]");
				return;
			}

			layout = new LogicalLayout(sensorDriver, controlDriver);

			sensorDriver.sensorTripped += new SensorTripped(sensorDriver_sensorTripped);
			sensorDriver.networkMessage += new NetworkMessage(sensorDriver_networkMessage);
			controlDriver.dataRecieved += new ResponseCallback(controlDriver_dataRecieved);
			layout.interconnectStateChanged += new InterconnectStateChanged(layout_interconnectStateChanged);
			layout.semaphoreEvent += new SemaphoreEvent(layout_semaphoreEvent);
			layout.signalChanged += new SignalChanged(layout_signalChanged);
			layout.trainSpeedChanged += new TrainSpeedChange(layout_trainSpeedChanged);

			string read;

			while ((read = System.Console.In.ReadLine()) != "quit")
			{
				string command = read.ToLower();
				if (command == "reset")
				{
					sensorDriver.reset();
				}
				else if (command == "startup")
				{
					sensorDriver.sendStartup();
				}
				else if (command[0] == 'p')
				{
					byte addr = 0;
					try
					{
						addr = Convert.ToByte(command.Substring(1));
						sensorDriver.ping(addr);
						System.Console.Out.WriteLine("Pinging address: {0}", addr);
					}
					catch (FormatException e)
					{
						System.Console.Error.WriteLine(e.Message);
						System.Console.Out.WriteLine("Must enter an address in the range 0 to 255 to ping.");
					}
					catch (ArgumentException e)
					{
						System.Console.Error.WriteLine(e.Message);
						System.Console.Out.WriteLine("Must enter an address in the range 0 to 255 to ping.");
					}
					catch (OverflowException e)
					{
						System.Console.Error.WriteLine(e.Message);
						System.Console.Out.WriteLine("The address must be in the range 0 to 255 to ping.");
					}
				}

			}
		}

		static void layout_trainSpeedChanged(int trainId, int speed, bool changeDirection)
		{
			Console.WriteLine("--Train Speed Changed--");
			Console.WriteLine("Id: " + trainId + Environment.NewLine + "Speed: " + speed + Environment.NewLine);
		}

		static void layout_signalChanged(int id, SignalState state)
		{
			Console.WriteLine("--Signal Changed--");
			Console.WriteLine("Id: " + id + Environment.NewLine + "State: " + state + Environment.NewLine);
		}

		static void layout_semaphoreEvent(Object block, Train train, SemaphoreAction action)
		{
			Console.WriteLine("--Semaphore Event--");
			Console.WriteLine("Block: " + block.ToString() + Environment.NewLine + "Train: " + train.Id + " - " + train.Name + Environment.NewLine + "Semaphore Action: " + action.ToString() + Environment.NewLine);
		}

		static void layout_interconnectStateChanged(int id, bool state)
		{
			Console.WriteLine("--Interconnect State Changed--");
			Console.WriteLine("Id: " + id + Environment.NewLine + "State: " + state + Environment.NewLine);
		}

		static void sensorDriver_networkMessage(string message)
		{
			System.Console.Out.WriteLine("Message received from network: " + message + Environment.NewLine + Environment.NewLine);
		}

		static void controlDriver_dataRecieved(string response)
		{
			System.Console.Out.WriteLine("Data Received from Controller: " + response + Environment.NewLine + Environment.NewLine);
		}

		static void sensorDriver_sensorTripped(int sensorId, int tagId, int trainId, double speed, bool direction, bool front)
		{
			layout.tripSensor(sensorId, trainId, (direction?Direction.Forward:Direction.Reverse), front);
			return;
		}
	}
}
